home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / GUSI / GUSINetDB.cp < prev    next >
Text File  |  1993-10-31  |  11KB  |  475 lines

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSINetDB.cp    -    Convert internet names to adresses
  4. Author    :    Matthias Neeracher
  5.  
  6.     This file was derived from the socket library by
  7.  
  8.         Charlie Reiman    <creiman@ncsa.uiuc.edu> and
  9.         Tom Milligan    <milligan@madhaus.utcs.utoronto.ca>
  10.  
  11. Started    :    12Sep92                                Language    :    MPW C++
  12.                 14Sep92    MN    Maybe it works, maybe it doesn't
  13.                 21Nov92    MN    Remove force_active
  14.                 19Jan93    MN    Can't set aliases to NULL.
  15.                 29Jul93    MN    Real getservent code (adapted from Sak Wathanasin)
  16.                 31Oct93    MN    Deferred opening of resolver
  17. Last        :    31Oct93
  18. *********************************************************************/
  19.  
  20. #include "GUSIINET_P.h"
  21.  
  22. #include "TFileSpec.h"
  23. #include "Folders.h"
  24. #include "PLStringFuncs.h"
  25.  
  26. #pragma segment GUSIResident
  27. pascal void DNRDone(struct hostInfo *, Boolean * done)
  28. {
  29.     *done = true;
  30. }
  31.  
  32. #pragma segment GUSIINET
  33.  
  34. int h_errno;
  35.  
  36. /*
  37.  *   Gethostbyname and gethostbyaddr each return a pointer to an
  38.  *   object with the following structure describing an Internet
  39.  *   host referenced by name or by address, respectively. This
  40.  *   structure contains the information obtained from the MacTCP
  41.  *   name server.
  42.  *
  43.  *   struct    hostent
  44.  *   {
  45.  *        char *h_name;
  46.  *        char **h_aliases;
  47.  *        int  h_addrtype;
  48.  *        int  h_length;
  49.  *        char **h_addr_list;
  50.  *   };
  51.  *   #define   h_addr  h_addr_list[0]
  52.  *
  53.  *   The members of this structure are:
  54.  *
  55.  *   h_name       Official name of the host.
  56.  *
  57.  *   h_aliases    A zero terminated array of alternate names for the host.
  58.  *
  59.  *   h_addrtype   The type of address being  returned; always AF_INET.
  60.  *
  61.  *   h_length     The length, in bytes, of the address.
  62.  *
  63.  *   h_addr_list  A zero terminated array of network addresses for the host.
  64.  *
  65.  *   Error return status from gethostbyname and gethostbyaddr  is
  66.  *   indicated by return of a null pointer.  The external integer
  67.  *   h_errno may then  be checked  to  see  whether  this  is  a
  68.  *   temporary  failure  or  an  invalid  or  unknown  host.  The
  69.  *   routine herror  can  be  used  to  print  an error  message
  70.  *   describing the failure.  If its argument string is non-NULL,
  71.  *   it is printed, followed by a colon and a space.   The  error
  72.  *   message is printed with a trailing newline.
  73.  *
  74.  *   h_errno can have the following values:
  75.  *
  76.  *     HOST_NOT_FOUND  No such host is known.
  77.  *
  78.  *     TRY_AGAIN    This is usually a temporary error and
  79.  *                    means   that  the  local  server  did  not
  80.  *                    receive a response from  an  authoritative
  81.  *                    server.   A  retry at some later time may
  82.  *                    succeed.
  83.  *
  84.  *     NO_RECOVERY    Some unexpected server failure was encountered.
  85.  *                     This is a non-recoverable error.
  86.  *
  87.  *     NO_DATA        The requested name is valid but  does  not
  88.  *                    have   an IP  address;  this  is not  a
  89.  *                    temporary error. This means that the  name
  90.  *                    is known  to the name server but there is
  91.  *                    no address  associated  with  this  name.
  92.  *                    Another type of request to the name server
  93.  *                    using this domain name will result in  an
  94.  *                    answer;  for example, a mail-forwarder may
  95.  *                    be registered for this domain.
  96.  *                    (NOT GENERATED BY THIS IMPLEMENTATION)
  97.  */
  98.  
  99. static struct hostInfo macHost;
  100.  
  101. #define MAXALIASES 0
  102. static char *aliasPtrs[MAXALIASES+1] = {NULL};
  103. static ip_addr *addrPtrs[NUM_ALT_ADDRS+1];
  104.  
  105. static struct hostent  unixHost =
  106. {
  107.     macHost.cname,
  108.     aliasPtrs,
  109.     AF_INET,
  110.     sizeof(ip_addr),
  111.     (char **) addrPtrs
  112. };
  113.  
  114. inline struct in_addr make_in_addr(ip_addr addr)
  115. {
  116.     struct in_addr    res;
  117.  
  118.     res.s_addr    =    addr;
  119.  
  120.     return res;
  121. }
  122.  
  123. struct hostent * gethostbyname(char *name)
  124. {
  125.     Boolean done;
  126.     int i;
  127.  
  128.     if (INETSockets.Resolver()) {
  129.         h_errno = NO_RECOVERY;    
  130.         return NULL;
  131.     }
  132.     
  133.     for (i=0; i<NUM_ALT_ADDRS; i++)
  134.         macHost.addr[i] = 0;
  135.  
  136.     done = false;
  137.  
  138.     if (StrToAddr(name, &macHost, ResultProcPtr(DNRDone), (char *) &done) == cacheFault)
  139.         SPINP(!done,SP_NAME,0L);
  140.  
  141.     switch (macHost.rtnCode) {
  142.     case noErr: break;
  143.  
  144.     case nameSyntaxErr:    h_errno = HOST_NOT_FOUND;    return(NULL);
  145.     case cacheFault:        h_errno = NO_RECOVERY;        return(NULL);
  146.     case noResultProc:    h_errno = NO_RECOVERY;        return(NULL);
  147.     case noNameServer:    h_errno = HOST_NOT_FOUND;    return(NULL);
  148.     case authNameErr:        h_errno = HOST_NOT_FOUND;    return(NULL);
  149.     case noAnsErr:            h_errno = TRY_AGAIN;            return(NULL);
  150.     case dnrErr:            h_errno = NO_RECOVERY;        return(NULL);
  151.     case outOfMemory:        h_errno = TRY_AGAIN;            return(NULL);
  152.     default:                    h_errno = NO_RECOVERY;        return(NULL);
  153.     }
  154.  
  155.     /* was the 'name' an IP address? */
  156.     if (macHost.cname[0] == 0) {
  157.         h_errno = HOST_NOT_FOUND;
  158.         return(NULL);
  159.     }
  160.  
  161.     /* for some reason there is a dot at the end of the name */
  162.     i = strlen(macHost.cname) - 1;
  163.     if (macHost.cname[i] == '.')
  164.         macHost.cname[i] = 0;
  165.  
  166.     for (i=0; i<NUM_ALT_ADDRS && macHost.addr[i]!=0; i++)
  167.         addrPtrs[i] =    (ip_addr *) &macHost.addr[i];
  168.  
  169.     addrPtrs[i] = NULL;
  170.  
  171.     return &unixHost;
  172. }
  173.  
  174. struct hostent * gethostbyaddr(const char *addrP, int, int)
  175. {
  176.     Boolean    done;
  177.     int         i;
  178.  
  179.     if (INETSockets.Resolver()) {
  180.         h_errno = NO_RECOVERY;    
  181.         return NULL;
  182.     }
  183.  
  184.     for (i=0; i<NUM_ALT_ADDRS; i++)
  185.         macHost.addr[i] = 0;
  186.  
  187.     done = false;
  188.  
  189.     if (AddrToName(*(ip_addr *)addrP, &macHost, ResultProcPtr(DNRDone), (char *) &done) == cacheFault)
  190.         SPINP(!done,SP_ADDR,0L);
  191.  
  192.     switch (macHost.rtnCode) {
  193.     case noErr:             break;
  194.  
  195.     case cacheFault:        h_errno = NO_RECOVERY;        return(NULL);
  196.     case noNameServer:    h_errno = HOST_NOT_FOUND;    return(NULL);
  197.     case authNameErr:        h_errno = HOST_NOT_FOUND;    return(NULL);
  198.     case noAnsErr:            h_errno = TRY_AGAIN;            return(NULL);
  199.     case dnrErr:            h_errno = NO_RECOVERY;        return(NULL);
  200.     case outOfMemory:        h_errno = TRY_AGAIN;            return(NULL);
  201.     default:                    h_errno = NO_RECOVERY;        return(NULL);
  202.     }
  203.  
  204.     /* for some reason there is a dot at the end of the name */
  205.     i = strlen(macHost.cname) - 1;
  206.     if (macHost.cname[i] == '.')
  207.         macHost.cname[i] = 0;
  208.  
  209.     for (i=0; i<NUM_ALT_ADDRS; i++)
  210.         addrPtrs[i] = (ip_addr *) &macHost.addr[i];
  211.  
  212.     addrPtrs[NUM_ALT_ADDRS] = NULL;
  213.  
  214.     return &unixHost;
  215. }
  216.  
  217. char * inet_ntoa(struct in_addr inaddr)
  218. {
  219.     if (INETSockets.Resolver()) {
  220.         h_errno = NO_RECOVERY;    
  221.         return NULL;
  222.     }
  223.     
  224.     (void) AddrToStr(inaddr.s_addr, macHost.cname);
  225.  
  226.     return macHost.cname;
  227. }
  228.  
  229. struct in_addr inet_addr(char *address)
  230. {
  231.     if (INETSockets.Resolver()) {
  232.         h_errno = NO_RECOVERY;    
  233.         return make_in_addr(0xFFFFFFFF);
  234.     }
  235.     
  236.     if (StrToAddr(address,&macHost,NULL,NULL) != noErr)
  237.         return make_in_addr(0xFFFFFFFF);
  238.  
  239.     /* was the 'address' really a name? */
  240.     if (macHost.cname[0] != 0)
  241.         return make_in_addr(0xFFFFFFFF);
  242.  
  243.     return make_in_addr(macHost.addr[0]);
  244. }
  245.  
  246. /*
  247.  * gethostname()
  248.  *
  249.  * Try to get my host name from DNR. If it fails, just return my
  250.  * IP address as ASCII. This is non-standard, but it's a mac,
  251.  * what do you want me to do?
  252.  */
  253.  
  254. int gethostname(char *machname, int buflen)
  255. {
  256.     in_addr ipaddr;
  257.     struct    hostent *hp;
  258.     struct GetAddrParamBlock pbr;
  259.  
  260.     pbr.ioCRefNum     = INETSockets.Driver();
  261.     pbr.csCode         = ipctlGetAddr;
  262.  
  263.     if (PBControlSync(ParmBlkPtr(&pbr)))
  264.         goto resign;
  265.  
  266.     ipaddr    =    make_in_addr(pbr.ourAddress);
  267.  
  268.     hp = gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET);
  269.  
  270.     if (!hp)
  271.         goto resign;
  272.     else
  273.         strncpy(machname, hp->h_name, unsigned(buflen));
  274.  
  275.     machname[buflen-1] = 0;  /* extra safeguard */
  276.  
  277.     return 0;
  278.  
  279. resign:
  280.     sprintf(machname, "%d.%d.%d.%d",
  281.                             ipaddr.s_addr>>24,
  282.                             ipaddr.s_addr>>16 & 0xff,
  283.                             ipaddr.s_addr>>8 & 0xff,
  284.                             ipaddr.s_addr & 0xff);
  285.     return 0;
  286. }
  287.  
  288.  
  289. /*
  290.  *    getservbybname()
  291.  *
  292.  */
  293.  
  294. static char * servlist[] =
  295. {
  296.     "echo             7/udp",
  297.     "discard         9/udp",
  298.     "time            37/udp",
  299.     "domain        53/udp",
  300.     "sunrpc       111/udp",
  301.     "tftp           69/udp",
  302.     "biff           512/udp",
  303.     "who           513/udp",
  304.     "talk           517/udp",
  305.     "ftp-data       20/tcp",
  306.     "ftp           21/tcp",
  307.     "telnet       23/tcp",
  308.     "smtp           25/tcp",
  309.     "time           37/tcp",
  310.     "whois           43/tcp",
  311.     "domain           53/tcp",
  312.     "hostnames  101/tcp",
  313.     "nntp           119/tcp",
  314.     "finger       79/tcp",
  315.     "ntp           123/tcp",
  316.     "uucp           540/tcp",
  317.     NULL
  318. };
  319.  
  320. static char                 servline[128];
  321. static struct servent    serv;
  322. static FILE *                 servfil;
  323. static int                    servptr;
  324. static char *                servalias[8];
  325. static int                    servstay = 0;
  326.  
  327. void setservent(int stayopen)
  328. {
  329.     if (servfil && servfil != (FILE *) -1) {
  330.         rewind(servfil);
  331.     }
  332.     servptr    = 0;
  333.     servstay = servstay || stayopen;
  334. }
  335.  
  336. void endservent()
  337. {
  338.     if (servfil && servfil != (FILE *) -1) {
  339.         fclose(servfil);
  340.         servfil = NULL;
  341.     }
  342.     
  343.     servstay = 0;
  344. }
  345.  
  346. struct servent *  getservent()
  347. {
  348.     char *    p;
  349.     int        aliascount;
  350.     
  351.     if (!servfil) {
  352.         TFileSpec serv;
  353.         
  354.         if (!FindFolder(
  355.                 kOnSystemDisk, 
  356.                 kPreferencesFolderType, 
  357.                 kDontCreateFolder, 
  358.                 &serv.vRefNum,
  359.                 &serv.parID)
  360.         ) {
  361.             PLstrcpy(serv.name, "\p/etc/services");
  362.         
  363.             if (servfil = fopen(serv.FullPath(), "r"))
  364.                 goto retry;
  365.         }    
  366.         servfil     = (FILE *) -1;
  367.         servptr    = 0;
  368.         
  369.         return (struct servent *) NULL;    
  370.     }
  371.     
  372. retry:
  373.     if (servfil == (FILE *) -1)
  374.         if (!servlist[servptr])
  375.             return (struct servent *) NULL;
  376.         else
  377.             strcpy(servline, servlist[servptr++]);
  378.     else if (!(fgets(servline, 128, servfil)))
  379.         return (struct servent *) NULL;
  380.         
  381.     if (p = strpbrk(servline, "#\n"))
  382.         *p = 0;
  383.     if (!servline[0])
  384.         goto retry;
  385.     
  386.     if (!(serv.s_name = strtok(servline, " \t")))
  387.         goto retry;
  388.         
  389.     if (!(p = strtok(NULL, " \t")))
  390.         goto retry;
  391.     
  392.     if (!(serv.s_proto = strpbrk(p, "/,")))
  393.         goto retry;
  394.         
  395.     *serv.s_proto++     = 0;
  396.     serv.s_port         = htons(atoi(p));
  397.     serv.s_aliases     = servalias;
  398.     
  399.     for (aliascount = 0; aliascount < 7; ) 
  400.         if (!(servalias[aliascount++] = strtok(NULL, " \t")))
  401.             break;
  402.     
  403.     servalias[aliascount] = NULL;
  404.     
  405.     return &serv;
  406. }
  407.  
  408. struct servent * getservbyname(const char * name, const char * proto)
  409. {
  410.     struct servent *     ent;
  411.     char **                 al;
  412.     setservent(0);
  413.     
  414.     while (ent = getservent()) {
  415.         if (!strcmp(name, ent->s_name))
  416.             goto haveName;
  417.         
  418.         for (al = ent->s_aliases; *al; ++al)
  419.             if (!strcmp(name, *al))
  420.                 goto haveName;
  421.         
  422.         continue;
  423. haveName:
  424.         if (!proto || !strcmp(proto, ent->s_proto))
  425.             break;
  426.     }
  427.     
  428.     if (!servstay)
  429.         endservent();
  430.     
  431.     return ent;
  432. }
  433.  
  434. struct servent * getservbyport(int port, const char * proto)
  435. {
  436.     struct servent * ent;
  437.     
  438.     setservent(0);
  439.     
  440.     while (ent = getservent())
  441.         if (port == ent->s_port && (!proto || !strcmp(proto, ent->s_proto)))
  442.             break;
  443.     
  444.     if (!servstay)
  445.         endservent();
  446.     
  447.     return ent;
  448. }
  449.  
  450. static    char    tcp[] = "tcp";
  451. static    char    udp[] = "udp";
  452. #define    MAX_PROTOENT            10
  453. static     struct protoent        protoents[MAX_PROTOENT];
  454. static     int                        protoent_count=0;
  455.  
  456. struct protoent * getprotobyname(const char * name)
  457. {
  458.     struct protoent *pe;
  459.  
  460.     pe = &protoents[protoent_count];
  461.     if (strcmp(name, "udp") == 0) {
  462.         pe->p_name = udp;
  463.         pe->p_proto = IPPROTO_UDP;
  464.     } else if (strcmp (name, "tcp") == 0)  {
  465.         pe->p_name = tcp;
  466.         pe->p_proto = IPPROTO_TCP;
  467.     } else {
  468.         errno = EPROTONOSUPPORT;
  469.         return NULL;
  470.     }
  471.     pe->p_aliases = aliasPtrs;
  472.     protoent_count = (protoent_count +1) % MAX_PROTOENT;
  473.     return pe;
  474. }
  475.